package test.helpers;


import java.io.*;
import java.util.*;
import java.util.Map.Entry;

import com.google.common.base.Charsets;
import com.google.common.collect.Sets;
import com.google.common.io.Files;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * @author cheremin
 * @since 03.03.12,  17:37
 */
public class Config {
    private final Map<String, String> properties = new HashMap<String, String>();

    public Config() {
    }

    public Config( final Properties properties ) {
        putProperties( properties );
    }

    private void putProperties( final Properties properties ) {
        for ( final Entry<Object, Object> entry : properties.entrySet() ) {
            this.properties.put(
                    ( String ) entry.getKey(),
                    ( String ) entry.getValue()
            );
        }
    }

    public static Config load( final File file ) throws IOException {
        if ( !file.exists() ) {
            return new Config();
        }
        final Properties p = new Properties();
        final BufferedReader r = Files.newReader( file, Charsets.US_ASCII );
        try {
            p.load( r );
            return new Config( p );
        } finally {
            r.close();
        }
    }

    public void append( final Properties p ) {
        putProperties( p );
    }

    private String getProperty( final String key ) {
        return properties.get( key );
    }

    public boolean hasProperty( final String key ) {
        return properties.containsKey( key );
    }

    private void checkKeyExists( final String key ) {
        checkArgument( hasProperty( key ), "Value for key[%s] does not exists", key );
    }

    public String getAsString( final String key ) throws IllegalArgumentException {
        checkKeyExists( key );
        return getProperty( key );
    }

    public String getAsString( final String key,
                               final String defValue ) {
        if ( hasProperty( key ) ) {
            return getProperty( key );
        } else {
            return defValue;
        }
    }

    public long getAsLong( final String key ) throws IllegalArgumentException {
        return Long.parseLong( getAsString( key ) );
    }

    public long getAsLong( final String key,
                           final long defValue ) {
        if ( hasProperty( key ) ) {
            return getAsLong( key );
        } else {
            return defValue;
        }
    }

    public int getAsInt( final String key ) throws IllegalArgumentException {
        return Integer.parseInt( getAsString( key ) );
    }

    public int getAsInt( final String key,
                         final int defValue ) {
        if ( hasProperty( key ) ) {
            return getAsInt( key );
        } else {
            return defValue;
        }
    }

    public double getAsDouble( final String key ) throws IllegalArgumentException {
        return Double.parseDouble( getAsString( key ) );
    }

    public double getAsDouble( final String key,
                               final double defValue ) {
        if ( hasProperty( key ) ) {
            return getAsDouble( key );
        } else {
            return defValue;
        }
    }

    public boolean getAsBoolean( final String key ) throws IllegalArgumentException {
        return Boolean.parseBoolean( getAsString( key ) );
    }

    public boolean getAsBoolean( final String key,
                                 final boolean defValue ) {
        if ( hasProperty( key ) ) {
            return getAsBoolean( key );
        } else {
            return defValue;
        }
    }

    public <T> Class<T> getAsClass( final String key ) throws IllegalArgumentException,
                                                              ClassNotFoundException {
        final String className = getAsString( key );
        return ( Class<T> ) Class.forName( className );
    }

    public <T> Class<? extends T> getAsClass( final String key,
                                              final Class<? extends T> defValue ) throws ClassNotFoundException {
        if ( hasProperty( key ) ) {
            return getAsClass( key );
        } else {
            return defValue;
        }
    }

    public <T> T newInstanceByClass( final String key,
                                     final T defaultValue ) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        final Class<? extends T> clazz = getAsClass( key, null );
        if ( clazz == null ) {
            return defaultValue;
        } else {
            return clazz.newInstance();
        }
    }

    public void print( final PrintStream ps ) {
        for ( final String key : Sets.newTreeSet( properties.keySet() ) ) {
            final String value = properties.get( key );
            ps.printf( "%s = %s\n", key, value );
        }
    }
}
